package com.xiaoxi.bms.service.menu.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoxi.bms.common.constant.enumeration.dict.MenuTypeEnums;
import com.xiaoxi.bms.common.constant.enumeration.statuscode.user.MenuUserEnums;
import com.xiaoxi.bms.common.exception.BMSException;
import com.xiaoxi.bms.common.util.AuthUtils;
import com.xiaoxi.bms.domain.menu.BMSMenu;
import com.xiaoxi.bms.domain.menu.query.BMSUserMenuMetaQuery;
import com.xiaoxi.bms.domain.menu.vo.BMSMenuTree;
import com.xiaoxi.bms.domain.menu.vo.BMSMenuVO;
import com.xiaoxi.bms.domain.menu.vo.BMSUserMenuTree;
import com.xiaoxi.bms.mapper.menu.BMSMenuMapper;
import com.xiaoxi.bms.mapper.role.BMSRoleMenuMapper;
import com.xiaoxi.bms.service.menu.BMSMenuService;
import com.xiaoxi.bms.service.role.BMSRoleMenuService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author xiaoxi
 * @version 1.0
 * @date 2022/6/1 18:55
 */
@Slf4j
@Service
public class BMSMenuServiceImpl extends ServiceImpl<BMSMenuMapper, BMSMenu> implements BMSMenuService {

    @Resource
    private BMSMenuMapper bmsMenuMapper;

    @Resource
    private BMSRoleMenuService bmsRoleMenuService;

    @Override
    public Boolean checkMenuIdListValid(List<Long> menuIds) {
        QueryWrapper<BMSMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", menuIds);
        List<BMSMenu> bmsMenuList = baseMapper.selectList(queryWrapper);
        return bmsMenuList.size() == menuIds.size();
    }

    @Override
    public List<BMSMenuTree> getMenuTree() {

        List<BMSMenu> bmsMenuList = baseMapper.selectList(new QueryWrapper<>());

        return calcBMSMenuTree(bmsMenuList);

    }

    @Override
    public List<BMSUserMenuTree> getUserMenuTree() {

        List<BMSMenu> bmsMenuList = bmsMenuMapper.getUserMenu(AuthUtils.getCurrentUser().getId());

        return calcBMSUserMenuTree(bmsMenuList);

    }


    @Override
    public void updateMenu(BMSMenuVO bmsMenuVO) throws BMSException {

        if (MenuTypeEnums.FIRST_MENU_TYPE_ENUMS.getCode().equals(bmsMenuVO.getType()) && checkRouteName(bmsMenuVO.getRouteName(), bmsMenuVO.getId())) {
            throw new BMSException(MenuUserEnums.THE_ROUTE_NAME_ALREADY_EXISTS);
        }


        if (checkTitleName(bmsMenuVO.getTitleName(), bmsMenuVO.getId())) {
            throw new BMSException(MenuUserEnums.THE_TITLE_NAME_ALREADY_EXISTS);
        }

        log.info("校验完毕,开始更新菜单：{}", bmsMenuVO);

        BMSMenu bmsMenu = new BMSMenu();
        BeanUtils.copyProperties(bmsMenuVO, bmsMenu);
        baseMapper.updateById(bmsMenu);
    }

    @Override
    public void createMenu(BMSMenuVO bmsMenuVO) throws BMSException {

        if (MenuTypeEnums.FIRST_MENU_TYPE_ENUMS.getCode().equals(bmsMenuVO.getType()) && checkRouteName(bmsMenuVO.getRouteName(), null)) {
            throw new BMSException(MenuUserEnums.THE_ROUTE_NAME_ALREADY_EXISTS);
        }

        if (checkTitleName(bmsMenuVO.getTitleName(), null)) {
            throw new BMSException(MenuUserEnums.THE_TITLE_NAME_ALREADY_EXISTS);
        }

        log.info("校验完毕,开始创建菜单：{}", bmsMenuVO);

        BMSMenu bmsMenu = new BMSMenu();
        BeanUtils.copyProperties(bmsMenuVO, bmsMenu);

        baseMapper.insert(bmsMenu);

    }

    @Override
    public BMSMenuVO findByOne(Long id) {
        BMSMenu bmsMenu = baseMapper.selectById(id);
        BMSMenuVO bmsMenuVO = new BMSMenuVO();
        BeanUtils.copyProperties(bmsMenu, bmsMenuVO);
        return bmsMenuVO;
    }

    @Override
    public void deleteMenuById(Long id) {

        String ids = bmsMenuMapper.findChildrenMenuWithMyself(id);
        String[] idArray = ids.split(",");
        List<String> allStringId = Arrays.asList(idArray);

        List<Long> allLongId = new ArrayList<>(allStringId.size());

        allStringId.forEach(str -> {
            allLongId.add(Long.parseLong(str));
        });

        baseMapper.deleteBatchIds(allLongId);

        bmsRoleMenuService.deleteRoleMenuByMenuIds(allLongId);

    }

    @Override
    public Boolean checkRouteName(String routeName, Long id) {
        QueryWrapper<BMSMenu> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(id)) {
            queryWrapper.ne("id", id);
        }
        queryWrapper.eq("route_name", routeName);
        long total = baseMapper.selectCount(queryWrapper);
        return total != 0;
    }

    @Override
    public Boolean checkTitleName(String titleName, Long id) {
        QueryWrapper<BMSMenu> queryWrapper = new QueryWrapper<>();
        if (Objects.nonNull(id)) {
            queryWrapper.ne("id", id);
        }
        queryWrapper.eq("title_name", titleName);
        long total = baseMapper.selectCount(queryWrapper);
        return total != 0;
    }

    /**
     * 计算菜单树
     *
     * @param bmsMenuList
     * @return
     */
    private List<BMSMenuTree> calcBMSMenuTree(List<BMSMenu> bmsMenuList) {
        // 1. 格式化 数据， parent --> children
        Map<Long, List<BMSMenu>> longListMap = new HashMap<>();

        // 2. 转 前端数据
        List<BMSMenuTree> bmsMenuTreeList = new ArrayList<>();

        //  1.1 格式化 数据， parent --> children
        for (BMSMenu bmsMenu : bmsMenuList) {


            // 只有大菜单才拥有权利支配树形结构
            if (bmsMenu.getParentId() == 0) {
                BMSMenuTree bmsMenuTree = new BMSMenuTree();
                bmsMenuTree.setId(bmsMenu.getId());
                bmsMenuTree.setLabel(bmsMenu.getTitleName());
                bmsMenuTree.setParentId(bmsMenu.getParentId());
                bmsMenuTree.setOrderBy(bmsMenu.getOrderBy());
                bmsMenuTreeList.add(bmsMenuTree);
            }

            setLongListMap(longListMap, bmsMenu);

        }


        //  2.1 递归处理 VO
        dfsBMSMenuTreeParentId(bmsMenuTreeList, longListMap);

        //  2.2 通过orderBy字段排序
        dfsBMSMenuTreeOrderBySort(bmsMenuTreeList);

        return bmsMenuTreeList;
    }


    /**
     * 递归 输出 父子关系的 组件
     *
     * @param bmsMenuTreeList 单个 菜单 内容
     * @param longListMap     父子关系
     */
    private void dfsBMSMenuTreeParentId(List<BMSMenuTree> bmsMenuTreeList, Map<Long, List<BMSMenu>> longListMap) {

        for (BMSMenuTree bmsMenuTree : bmsMenuTreeList) {

            List<BMSMenu> children = longListMap.get(bmsMenuTree.getId());

            if (Objects.isNull(children)) {
                continue;
            }

            List<BMSMenuTree> bmsMenuTrees = new ArrayList<>();

            for (BMSMenu bmsMenu : children) {
                BMSMenuTree menuTree = new BMSMenuTree();
                menuTree.setId(bmsMenu.getId());
                menuTree.setLabel(bmsMenu.getTitleName());
                menuTree.setParentId(bmsMenu.getParentId());
                menuTree.setOrderBy(bmsMenu.getOrderBy());
                bmsMenuTrees.add(menuTree);
            }

            dfsBMSMenuTreeParentId(bmsMenuTrees, longListMap);

            bmsMenuTree.setChildren(bmsMenuTrees);

        }
    }

    /**
     * 菜单排序
     *
     * @param bmsMenuTreeList 待排序的菜单
     */
    private void dfsBMSMenuTreeOrderBySort(List<BMSMenuTree> bmsMenuTreeList) {

        if (Objects.isNull(bmsMenuTreeList) || bmsMenuTreeList.size() == 0) {
            return;
        }

        // 1. 排序
        bmsMenuTreeList.sort(new Comparator<BMSMenuTree>() {
            @Override
            public int compare(BMSMenuTree o1, BMSMenuTree o2) {
                return o1.getOrderBy() - o2.getOrderBy();
            }
        });

        // 2. 递归取 子菜单
        for (BMSMenuTree bmsMenuTree : bmsMenuTreeList) {
            dfsBMSMenuTreeOrderBySort(bmsMenuTree.getChildren());
        }

    }


    private List<BMSUserMenuTree> calcBMSUserMenuTree(List<BMSMenu> bmsMenuList) {

        // 1. 格式化 数据， parent --> children
        Map<Long, List<BMSMenu>> longListMap = new HashMap<>();

        // 2. 转 前端数据
        List<BMSUserMenuTree> bmsUserMenuTreeList = new ArrayList<>();

        //  1.1 格式化 数据， parent --> children
        for (BMSMenu bmsMenu : bmsMenuList) {


            // 只有大菜单才拥有权利支配树形结构
            if (bmsMenu.getParentId() == 0) {

                bmsUserMenuTreeList.add(setBMSUserMenuTree(bmsMenu, "", ""));

            }

            setLongListMap(longListMap, bmsMenu);

        }


        //  2.1 递归处理 VO
        dfsBMSUserMenuParentId(bmsUserMenuTreeList, longListMap);

        //  2.2 通过orderBy字段排序
        dfsBMSUserMenuOrderBySort(bmsUserMenuTreeList);

        return bmsUserMenuTreeList;
    }

    /**
     * 递归 输出 父子关系的 组件
     *
     * @param bmsUserMenuTreeList 单个 菜单 内容
     * @param longListMap         父子关系
     */
    private void dfsBMSUserMenuParentId(List<BMSUserMenuTree> bmsUserMenuTreeList, Map<Long, List<BMSMenu>> longListMap) {

        for (BMSUserMenuTree bmsUserMenuTree : bmsUserMenuTreeList) {

            List<BMSMenu> children = longListMap.get(bmsUserMenuTree.getMeta().getId());

            if (Objects.isNull(children)) {
                continue;
            }

            List<BMSUserMenuTree> bmsUserMenuTrees = new ArrayList<>();

            for (BMSMenu bmsMenu : children) {

                bmsUserMenuTrees.add(setBMSUserMenuTree(bmsMenu, bmsUserMenuTree.getPath(), bmsUserMenuTree.getMeta().getBreadRumbs()));

            }

            dfsBMSUserMenuParentId(bmsUserMenuTrees, longListMap);

            bmsUserMenuTree.setChildren(bmsUserMenuTrees);

        }
    }

    /**
     * 菜单排序
     *
     * @param bmsUserMenuTreeList 待排序的菜单
     */
    private void dfsBMSUserMenuOrderBySort(List<BMSUserMenuTree> bmsUserMenuTreeList) {

        if (Objects.isNull(bmsUserMenuTreeList) || bmsUserMenuTreeList.size() == 0) {
            return;
        }

        // 1. 排序
        bmsUserMenuTreeList.sort(new Comparator<BMSUserMenuTree>() {
            @Override
            public int compare(BMSUserMenuTree o1, BMSUserMenuTree o2) {
                return o1.getMeta().getOrderBy() - o2.getMeta().getOrderBy();
            }
        });

        // 2. 递归取 子菜单
        for (BMSUserMenuTree bmsUserMenuTree : bmsUserMenuTreeList) {
            dfsBMSUserMenuOrderBySort(bmsUserMenuTree.getChildren());
        }

    }


    /**
     * 保存原数据
     *
     * @param longListMap
     * @param bmsMenu
     */
    private void setLongListMap(Map<Long, List<BMSMenu>> longListMap, BMSMenu bmsMenu) {
        long key = bmsMenu.getParentId();
        List<BMSMenu> menuList = longListMap.get(key);

        if (Objects.isNull(menuList)) {
            menuList = new ArrayList<>();
        }
        menuList.add(bmsMenu);
        longListMap.put(key, menuList);
    }

    /**
     * 抽象代码
     *
     * @param bmsMenu
     * @return
     */
    private BMSUserMenuTree setBMSUserMenuTree(BMSMenu bmsMenu, String path, String breadRumbs) {
        BMSUserMenuTree bmsUserMenuTree = new BMSUserMenuTree();
        bmsUserMenuTree.setPath(path + bmsMenu.getUrl());
        bmsUserMenuTree.setName(bmsMenu.getRouteName());
        BMSUserMenuMetaQuery bmsUserMenuMetaQuery = new BMSUserMenuMetaQuery();
        bmsUserMenuMetaQuery.setId(bmsMenu.getId());
        bmsUserMenuMetaQuery.setRequireAuth(true);
        if (StringUtils.isNotEmpty(breadRumbs)) {
            bmsUserMenuMetaQuery.setBreadRumbs(breadRumbs + "," + bmsMenu.getTitleName());
        } else {
            bmsUserMenuMetaQuery.setBreadRumbs(bmsMenu.getTitleName());
        }
        bmsUserMenuMetaQuery.setType(bmsMenu.getType());
        bmsUserMenuMetaQuery.setOrderBy(bmsMenu.getOrderBy());
        bmsUserMenuMetaQuery.setPermissionCode(bmsMenu.getPermissionCode());
        bmsUserMenuMetaQuery.setIconName(bmsMenu.getIconName());
        bmsUserMenuTree.setMeta(bmsUserMenuMetaQuery);
        bmsUserMenuTree.setComponent(bmsMenu.getComponent());
        bmsUserMenuTree.setParentId(bmsMenu.getParentId());
        return bmsUserMenuTree;
    }


}
